/**
 * @author		Ben Layet
 * @version 	0.1
 * @date		3 Sep 2008
 */
package org.learnaholic.application.model.xml;

import java.io.InputStream;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.learnaholic.application.model.ItemProperty;
import org.learnaholic.application.model.ListItem;
import org.learnaholic.application.model.ListItemImpl;
import org.learnaholic.application.model.MemoryItem;
import org.learnaholic.application.model.MemoryItemImpl;
import org.learnaholic.application.model.MemoryItems;
import org.learnaholic.application.model.MemoryItemsImpl;
import org.learnaholic.application.model.TestDialogDefinition;
import org.learnaholic.application.model.TestDialogElementDefinition;
import org.learnaholic.application.model.TestResult;
import org.learnaholic.application.model.TestResultLog;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

/**
 * XML Parser of an Item list.
 */
public class ItemListParser
{

	 //Format for EDT Time
   static final DateFormat gmtFormat = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss zzz");
	
	/**
	 * Parses XML data representing a list of MemoryItem.
	 * 
	 * @param in
	 *            the XML data.
	 * @return the list of MemoryItem
	 * @throws LearnaholicXmlException
	 *             if a parsing error occurs.
	 */
	public Map<String, ListItem> parse(InputStream in) throws LearnaholicXmlException
	{
		// the return value
		Map<String, ListItem> ret = new LinkedHashMap<String, ListItem>();

		try
		{
			DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
			DocumentBuilder db = dbf.newDocumentBuilder();
			Document doc = db.parse(in);
			doc.getDocumentElement().normalize();
			NodeList nodeLst = doc.getElementsByTagName("item");

			for (int s = 0; s < nodeLst.getLength(); s++)
			{

				Map<String,ItemProperty> properties = new HashMap<String,ItemProperty>();
				String value;
				
				Node fstNode = nodeLst.item(s);
				if (fstNode.getNodeType() == Node.ELEMENT_NODE)
				{
					Element fstElmnt = (Element) fstNode;
					String id = fstElmnt.getAttribute("id");
					String keyProperty;
					

					NodeList keyNodes =  fstElmnt.getElementsByTagName("key");

					if(keyNodes.getLength() != 1)
					{
						throw new LearnaholicXmlException("item id " + id + " has " + keyNodes.getLength() + " key element. It should have 1 and only 1.");
					}
					
					Node keyNode = keyNodes.item(0);

					Element keyElem = (Element) keyNode;
					keyProperty = keyElem.getAttribute("name");
					value = ((Node)keyElem.getChildNodes().item(0)).getNodeValue();
					properties.put(keyProperty, new ItemProperty(value));
					
					
					NodeList propertyNodes =  fstElmnt.getElementsByTagName("property");

					for (int p = 0; p < propertyNodes.getLength(); p++)
					{
						Node propertyNode = propertyNodes.item(p);

						if (propertyNode.getNodeType() == Node.ELEMENT_NODE)
						{
							Element propertyElement = (Element) propertyNode;
							String name = propertyElement.getAttribute("name");
							NodeList list = propertyElement.getChildNodes();
							if(list.getLength() > 0)
							{
								value = ((Node)propertyElement.getChildNodes().item(0)).getNodeValue();
								properties.put(name, new ItemProperty(value));
							}
						}
					}
					
					ListItem item = new ListItemImpl(id, keyProperty, properties);
					ret.put(id, item);
				}
				else
				{
					throw new LearnaholicXmlException("<item> node should not contain text.");
				}

			}
		}
		catch (Exception e)
		{
			e.printStackTrace();
		}

		// return the result
		return ret;
	}

	public MemoryItems loadXmlResult(InputStream resultsData, Map<String, ListItem> items) throws LearnaholicXmlException
	{
		MemoryItems ret = new MemoryItemsImpl();

		for (Iterator<String> iterator = items.keySet().iterator(); iterator.hasNext();)
		{
			String id = iterator.next();
			ListItem listItem = items.get(id);
			ret.put(id, new MemoryItemImpl(listItem));
		}
		
		try
		{
			DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
			DocumentBuilder db = dbf.newDocumentBuilder();
			Document doc = db.parse(resultsData);
			doc.getDocumentElement().normalize();
			NodeList nodeLst = doc.getElementsByTagName("item");
			
			for (int s = 0; s < nodeLst.getLength(); s++)
			{

				Map<String,ItemProperty> properties = new HashMap<String,ItemProperty>();
				String value;
				
				Node fstNode = nodeLst.item(s);
				if (fstNode.getNodeType() == Node.ELEMENT_NODE)
				{
					Element fstElmnt = (Element) fstNode;
					String id = fstElmnt.getAttribute("id");
					

					MemoryItem item = ret.get(id);
					
					if(null != item)
					{

						TestResultLog testResultLog = item.getTestResultLog();
						

						NodeList testList = fstElmnt.getElementsByTagName("test");
						for (int t = 0; t < testList.getLength(); t++)
						{

							Node testNode = testList.item(t);
							
							if (testNode != null && testNode.getNodeType() == Node.ELEMENT_NODE)
							{

								Element testElement = (Element) testNode;
								String dateString = testElement.getAttribute("date");
								String successString = testElement.getAttribute("result");

								Date date = gmtFormat.parse(dateString);
								TestResult result = TestResult.valueOf(successString);
								testResultLog.put(date, result);
							}
						}
					}
					else
					{
						System.err.println("Item id '" + id + "' does not exists. Result log will be deleted.");
					}

					
//					MemoryItem item = new MemoryItemImpl(properties);
//					ret.put(item.getProperty(keyPropertyName).getValue(), new MemoryItemImpl(properties));
				}
				else
				{
					throw new LearnaholicXmlException("<item> node should not contain text.");
				}

				

			}
		}
		catch (Exception e)
		{
			e.printStackTrace();
		}
		
		
		return ret;
	}

	public MemoryItems loadXml(InputStream listData, InputStream resultsData) throws LearnaholicXmlException
	{
		return loadXmlResult(resultsData, parse(listData));
	}
	
	public TestDialogDefinition loadTestDialogDefinition(InputStream testDialogDefinitionData) 
	{
		TestDialogDefinition ret = new TestDialogDefinition();
		
		try
		{
			DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
			DocumentBuilder db = dbf.newDocumentBuilder();
			Document doc = db.parse(testDialogDefinitionData);
			doc.getDocumentElement().normalize();
			NodeList nodeLst = doc.getElementsByTagName("element");
			
			for (int s = 0; s < nodeLst.getLength(); s++)
			{

				Map<String,ItemProperty> properties = new HashMap<String,ItemProperty>();
				String value;
				
				Node fstNode = nodeLst.item(s);
				if (fstNode.getNodeType() == Node.ELEMENT_NODE)
				{
					Element fstElmnt = (Element) fstNode;
					String type = fstElmnt.getAttribute("type");
					String name = fstElmnt.getAttribute("name");
					String property = fstElmnt.getAttribute("property");
					String checker = fstElmnt.getAttribute("checker");
					
					ret.add(new TestDialogElementDefinition(name, property, type, checker));
				}
				else
				{
					throw new LearnaholicXmlException("<element> node should not contain text.");
				}

				

			}
		}
		catch (Exception e)
		{
			e.printStackTrace();
		}
		
		return ret;
	}
}
